unit uDZSysInfo;

interface

uses
  Windows;

const
  PROCESSOR_ARCHITECTURE_AMD64 = 9;
  PROCESSOR_ARCHITECTURE_IA64 = 6;
  PROCESSOR_ARCHITECTURE_INTEL = 0;
  PROCESSOR_ARCHITECTURE_UNKNOWN = $ffff;
  
type
  TOSVersionInfoExA = record
    dwOSVersionInfoSize: DWORD;
    dwMajorVersion: DWORD;
    dwMinorVersion: DWORD;
    dwBuildNumber: DWORD;
    dwPlatformId: DWORD;
    szCSDVersion: array [0..127] of AnsiChar;
    wServicePackMajor: Word;
    wServicePackMinor: Word;
    wSuiteMask: Word;
    wProductType: Byte;
    wReserved: Byte;
  end;
  POSVersionInfoExA = ^TOSVersionInfoExA;

  TOSVersionInfoExW = record
    dwOSVersionInfoSize: DWORD;
    dwMajorVersion: DWORD;
    dwMinorVersion: DWORD;
    dwBuildNumber: DWORD;
    dwPlatformId: DWORD;
    szCSDVersion: array [0..127] of WideChar;
    wServicePackMajor: Word;
    wServicePackMinor: Word;
    wSuiteMask: Word;
    wProductType: Byte;
    wReserved: Byte;
  end;
  POSVersionInfoExW = ^TOSVersionInfoExW;

  {$ifdef unicode}
  TOSVersionInfoEx = TOSVersionInfoExW;
  POSVersionInfoEx = POSVersionInfoExW;
  {$else}
  TOSVersionInfoEx = TOSVersionInfoExA;
  POSVersionInfoEx = TOSVersionInfoExA;
  {$endif}

  NTSTATUS = Longint;
  SYSTEM_INFORMATION_CLASS = (
    SystemBasicInformation,
    SystemProcessorInformation,
    SystemPerformanceInformation,
    SystemTimeOfDayInformation,
    SystemPathInformation,
    SystemProcessInformation,
    SystemCallCountInformation,
    SystemDeviceInformation,
    SystemProcessorPerformanceInformation,
    SystemFlagsInformation,
    SystemCallTimeInformation,
    SystemModuleInformation,
    SystemLocksInformation,
    SystemStackTraceInformation,
    SystemPagedPoolInformation,
    SystemNonPagedPoolInformation,
    SystemHandleInformation,
    SystemObjectInformation,
    SystemPageFileInformation,
    SystemVdmInstemulInformation,
    SystemVdmBopInformation,
    SystemFileCacheInformation,
    SystemPoolTagInformation,
    SystemInterruptInformation,
    SystemDpcBehaviorInformation,
    SystemFullMemoryInformation,
    SystemLoadGdiDriverInformation,
    SystemUnloadGdiDriverInformation,
    SystemTimeAdjustmentInformation,
    SystemSummaryMemoryInformation,
    SystemNextEventIdInformation,
    SystemEventIdsInformation,
    SystemCrashDumpInformation,
    SystemExceptionInformation,
    SystemCrashDumpStateInformation,
    SystemKernelDebuggerInformation,
    SystemContextSwitchInformation,
    SystemRegistryQuotaInformation,
    SystemExtendServiceTableInformation,
    SystemPrioritySeperation,
    SystemPlugPlayBusInformation,
    SystemDockInformation,
    SystemPowerInformation,
    SystemProcessorSpeedInformation,
    SystemCurrentTimeZoneInformation,
    SystemLookasideInformation);
  TSystemInformationClass = SYSTEM_INFORMATION_CLASS;

  SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION = record
    IdleTime: Int64;
    KernelTime: Int64;
    UserTime: Int64;
    Reserved1: array [0..1] of Int64;
    Reserved2: ULONG;
  end;
  TSystemProcessorPerformanceInformation = SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
  PSystemProcessorPerformanceInformation = ^SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;

  TCPUPerformance = class
  private
    fOldKernelTime: array of Int64;
    fOldIdleTime: array of Int64;
    fOldUserTime: array of Int64;
    fUsage: array of Integer;
    fTotalUsage: Integer;
    PerfInfo: array of TSystemProcessorPerformanceInformation;
    function GetUsage(index: Integer): Integer;
  public
    constructor Create;
    destructor Destroy; override;
    procedure CalcUsage;
    property Usage[index: Integer]: Integer read GetUsage;
    property TotalUsage: Integer read fTotalUsage;
  end;
  
function NtQuerySystemInformation(
  InfoClass: SYSTEM_INFORMATION_CLASS;
  info: Pointer;
  InfoLength: ULONG;
  ReturnLength: PULONG): NTSTATUS; stdcall;

function GetProcessorCount: Integer;

function IsWin64OS: Boolean;
function IsWow64Process(hProc: THandle): Boolean;
procedure GetNativeSystemInfo(var SystemInfo: TSystemInfo); 

implementation

type
  TProc_IsWow64Process = function(hProc: THandle; var Res: BOOL): BOOL; stdcall;
  TProc_GetNativeSystemInfo = procedure(var lpSystemInfo: TSystemInfo); stdcall;

function NtQuerySystemInformation; external 'ntdll.dll'
  name 'NtQuerySystemInformation';

function GetProcessorCount: Integer;
var
  sysinfo: TSystemInfo;
begin
  GetSystemInfo(sysinfo);
  Result := sysinfo.dwNumberOfProcessors;
end;

procedure GetNativeSystemInfo(var SystemInfo: TSystemInfo);
var
  func: TProc_GetNativeSystemInfo;
begin
  func := GetProcAddress(GetModuleHandle('kernel32.dll'),'GetNativeSystemInfo');
  if Assigned(func) then func(SystemInfo)
  else GetSystemInfo(SystemInfo);
end;

function IsWin64OS: Boolean;
var
  info: TSystemInfo;
begin
  GetNativeSystemInfo(info);
  Result := (info.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64) or
    (info.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64);
end;

function IsWow64Process(hProc: THandle): Boolean;
var
  ModuleHandle: THandle;
  func: TProc_IsWow64Process;
  res: BOOL;
const
  PROCESSOR_ARCHITECTURE_AMD64 = 9;  
  PROCESSOR_ARCHITECTURE_IA64 = 6;
begin
  ModuleHandle := LoadLibrary('kernel32.dll');
  if ModuleHandle <> 0 then
  begin
    func := GetProcAddress(ModuleHandle, 'IsWow64Process');
    Result := Assigned(func) and func(hProc, res) and res;
  end
  else Result := False;
end;
  
{ TCPUPerformance }

procedure TCPUPerformance.CalcUsage;
var
  cb: ULONG;
  i: Integer;
  udiff, tdiff, udifft, tdifft: Int64;
begin
  if NtQuerySystemInformation(SystemProcessorPerformanceInformation,
    @PerfInfo[0], Length(PerfInfo) * SizeOf(PerfInfo[0]), @cb) = 0 then
  begin
    udifft := 0;
    tdifft := 0;
    for i := 0 to Length(PerfInfo) - 1 do
    begin
      udiff := PerfInfo[i].UserTime - fOldUserTime[i] +
        PerfInfo[i].KernelTime - PerfInfo[i].IdleTime -
       (fOldKernelTime[i] - fOldIdleTime[i]);

      tdiff :=  PerfInfo[i].KernelTime + PerfInfo[i].UserTime -
        fOldKernelTime[i] - fOldUserTime[i];

      Inc(udifft, udiff);
      Inc(tdifft, tdiff);

      fUsage[i] := Trunc(udiff*100.0/tdiff);

      fOldKernelTime[i] := PerfInfo[i].KernelTime;
      fOldIdleTime[i] := PerfInfo[i].IdleTime;
      fOldUserTime[i] := PerfInfo[i].UserTime;
    end;
    fTotalUsage := Trunc(udifft*100.0/tdifft);
  end;
end;

constructor TCPUPerformance.Create;
var
  i, ncpu: Integer;
  cb: ULONG;
begin
  inherited;
  ncpu := GetProcessorCount;
  SetLength(fOldKernelTime, ncpu);
  SetLength(fOldIdleTime, ncpu);
  SetLength(fOldUserTime, ncpu);
  SetLength(fUsage, ncpu);
  SetLength(PerfInfo, ncpu);
  if NtQuerySystemInformation(SystemProcessorPerformanceInformation,
    @PerfInfo[0], Length(PerfInfo) * SizeOf(PerfInfo[0]), @cb) = 0 then
  begin
    for i := 0 to ncpu - 1 do
    begin
      fOldKernelTime[i] := PerfInfo[i].KernelTime;
      fOldIdleTime[i] := PerfInfo[i].IdleTime;
      fOldUserTime[i] := PerfInfo[i].UserTime;
    end;
  end;
end;

destructor TCPUPerformance.Destroy;
begin

  inherited;
end;

function TCPUPerformance.GetUsage(index: Integer): Integer;
begin
  Result := fUsage[index];
end;

end.
